﻿Imports System.Text.RegularExpressions

Public Class ClassMarqueur
    'Classe permettant d'appliquer une expression régulière comme masque de recherche
    'sur les documents ouverts et de marquer les résultats en couleur.

    Public Titre As String
    Public sMasque As String
    Public CoulFondPrimaire As String
    Public CoulFondSecondaire As String
    Public CoulTextePrimaire As String
    Public CoulTexteSecondaire As String
    'Public Souligne As String
    Public Actif As Boolean
    Public TestTexte As String
    Public Modele As String
    Public CleTri As String
    Public SensibleCasse As String
    Public Multi As String
    Public Propager As String
    Private iTrouve As Integer
    Public Condition As String
    Public AutoCoulTextePrimaire As String

    Public Sub New()
        Me.Titre = "Nouveau"
        Me.sMasque = ".*"
        Me.CoulFondPrimaire = Commun.GetDefaultCoul("")
        Me.CoulFondSecondaire = Commun.GetCoulComp(Me.CoulFondPrimaire)
        Me.CoulTextePrimaire = System.Drawing.ColorTranslator.ToHtml(Color.Black)
        Me.CoulTexteSecondaire = System.Drawing.ColorTranslator.ToHtml(Color.Black)
        Me.TestTexte = ""
        Me.Modele = "$0"
        Me.Actif = True
        Me.iTrouve = 0
        Me.SensibleCasse = Boolean.FalseString
        Me.Multi = Boolean.FalseString
        Me.Propager = Boolean.FalseString
        'Me.Souligne = Boolean.FalseString
        Me.Condition = ""
        Me.AutoCoulTextePrimaire = Boolean.FalseString
        Me.CleTri = "$0"
    End Sub

    Public Sub New(ByVal Titre As String)
        Call Me.New()
        Me.Titre = Titre
    End Sub

    Public ReadOnly Property Masque As String
        Get
            If Me.sMasque.Contains("%") Then
                Return Me.ExpandMasque()
            Else
                Return Me.sMasque
            End If
        End Get
    End Property

    Public Function ExpandMasque() As String
        Dim Expanded As String = Me.sMasque
        For Each oMatch As Match In Regex.Matches(Me.sMasque, "%(.+?)%", RegexOptions.IgnoreCase)
            If Form1.ListViewMarqueurs.Items.ContainsKey(oMatch.Groups(1).Value) And (oMatch.Groups(1).Value <> Me.Titre) Then
                Expanded = Expanded.Replace(oMatch.Value, Form1.ListViewMarqueurs.Items(oMatch.Groups(1).Value).Tag.Masque)
            Else
                Expanded = Expanded.Replace(oMatch.Value, ".*?")
            End If
        Next
        Return Expanded
    End Function

    Public Function Edition() As Boolean
        Dim oForm As New FormMarqueur
        oForm.TextBoxTitre.Text = Me.Titre
        oForm.TextBoxRegEx.Text = Me.sMasque
        oForm.TextBoxFondPrimaire.Text = Me.CoulFondPrimaire
        oForm.TextBoxFondSecondaire.Text = Me.CoulFondSecondaire
        oForm.TextBoxTextePrimaire.Text = Me.CoulTextePrimaire
        oForm.TextBoxTexteSecondaire.Text = Me.CoulTexteSecondaire
        oForm.RichTextBoxTest.Text = Me.TestTexte
        oForm.CheckBoxCasse.Checked = (Me.SensibleCasse = Boolean.TrueString)
        oForm.CheckBoxPropager.Checked = (Me.Propager = Boolean.TrueString)
        'oForm.CheckBoxSouligne.Checked = (Me.Souligne = Boolean.TrueString)
        oForm.CheckBoxMulti.Checked = (Me.Multi = Boolean.TrueString)
        oForm.TextBoxModele.Text = Me.Modele
        oForm.TextBoxCondition.Text = Me.Condition
        oForm.CheckBoxCoulAuto.Checked = (Me.AutoCoulTextePrimaire = Boolean.TrueString)
        oForm.TextBoxCleTri.Text = Me.CleTri
        If oForm.ShowDialog() = DialogResult.OK Then
            Me.Titre = oForm.TextBoxTitre.Text
            Me.sMasque = oForm.TextBoxRegEx.Text
            Me.TestTexte = oForm.RichTextBoxTest.Text
            Me.CoulFondPrimaire = oForm.TextBoxFondPrimaire.Text
            Me.CoulFondSecondaire = oForm.TextBoxFondSecondaire.Text
            Me.CoulTextePrimaire = oForm.TextBoxTextePrimaire.Text
            Me.CoulTexteSecondaire = oForm.TextBoxTexteSecondaire.Text
            Me.SensibleCasse = oForm.CheckBoxCasse.Checked.ToString
            Me.Propager = oForm.CheckBoxPropager.Checked.ToString
            'Me.Souligne = oForm.CheckBoxSouligne.Checked.ToString
            Me.Multi = oForm.CheckBoxMulti.Checked.ToString
            Me.AutoCoulTextePrimaire = oForm.CheckBoxCoulAuto.Checked.ToString
            Me.Modele = oForm.TextBoxModele.Text
            Me.Condition = oForm.TextBoxCondition.Text
            Me.CleTri = oForm.TextBoxCleTri.Text
            oForm = Nothing
            Return True
        Else
            oForm = Nothing
            Return False
        End If
    End Function

    Public Sub ResetCompteur()
        'Debug.Print("Reset " & Me.Titre & " à zéro")
        Me.iTrouve = 0
    End Sub

    Public Sub IncCompteur()
        Me.iTrouve += 1
    End Sub

    Public Property Compteur() As Integer
        Get
            Return Me.iTrouve
        End Get
        Set(ByVal value As Integer)
            'Debug.Print("Set " & Me.Titre & " = " & value)
            Me.iTrouve = value
        End Set
    End Property

    Public Function SubMatchesToString(ByVal Chaine As String, ByVal AppliqueCondition As Boolean) As String
        Dim oColMatch As MatchCollection
        Dim oCode As New ClassMacro 'Pour évaluation des conditions
        Dim Options As RegexOptions = RegexOptions.Multiline
        If Me.SensibleCasse = Boolean.FalseString Then Options = Options Or RegexOptions.IgnoreCase
        If Me.Multi = Boolean.TrueString Then Options = Options Or RegexOptions.Singleline
        Dim sResult As String = ""
        Try
            oColMatch = System.Text.RegularExpressions.Regex.Matches(Chaine, Me.Masque, Options)
            For Each oMatch As Match In oColMatch
                Dim bRetenu As Boolean = True
                If AppliqueCondition And (Me.Condition <> "") Then bRetenu = oCode.EvalCondition(oMatch, Me.Condition)
                If bRetenu Then
                    If oMatch.Groups.Count >= 1 Then
                        For iSubMatch As Integer = 1 To oMatch.Groups.Count - 1
                            sResult &= "$" & iSubMatch.ToString("0") & " " & oMatch.Groups(iSubMatch).Value & vbCrLf
                        Next
                    End If
                End If
            Next
        Catch Ex As Exception
        End Try
        Return sResult
    End Function

    Public Function Extraire(ByVal Chaine As String) As String
        Dim oColMatch As MatchCollection
        Dim oCode As New ClassMacro 'Pour évaluation des conditions
        Dim Options As RegexOptions = RegexOptions.Multiline
        If Me.SensibleCasse = Boolean.FalseString Then Options = Options Or RegexOptions.IgnoreCase
        If Me.Multi = Boolean.TrueString Then Options = Options Or RegexOptions.Singleline
        Dim sResult As String = ""
        Try
            oColMatch = System.Text.RegularExpressions.Regex.Matches(Chaine, Me.Masque, Options)
            For Each oMatch As Match In oColMatch
                Dim bRetenu As Boolean = True
                If Me.Condition <> "" Then bRetenu = oCode.EvalCondition(oMatch, Me.Condition)
                If bRetenu Then
                    Dim sFormate As String = Me.Modele
                    For iSubMatch As Integer = 0 To oMatch.Groups.Count - 1
                        sFormate = sFormate.Replace("$" & iSubMatch.ToString("0"), oMatch.Groups(iSubMatch).Value)
                        sFormate = Regex.Replace(sFormate, "\$No", oMatch.Index.ToString("0"), RegexOptions.IgnoreCase)
                    Next
                    sResult &= sFormate & vbCrLf
                End If
            Next
        Catch Ex As Exception
        End Try
        Return sResult
    End Function

    Public Function Tri(ByVal Chaine As String) As String
        Dim oCode As New ClassMacro 'Pour évaluation des conditions
        Dim Options As RegexOptions = RegexOptions.Multiline
        If Me.SensibleCasse = Boolean.FalseString Then Options = Options Or RegexOptions.IgnoreCase
        If Me.Multi = Boolean.TrueString Then Options = Options Or RegexOptions.Singleline
        Dim oColMatch As MatchCollection
        Try
            oColMatch = Regex.Matches(Chaine, Me.Masque, Options)
        Catch Ex As Exception
            Return ""
        End Try
        'Construire la liste des valeurs triées par clés
        Dim tCles(oColMatch.Count - 1) As String 'Cles pour le tri
        Dim tValeurs(oColMatch.Count - 1) As String 'Valeur correspondant à la clé
        Dim i As Integer = 0
        For Each oMatch As Match In oColMatch
            tCles(i) = Regex.Replace(oMatch.Value, Me.Masque, Me.CleTri, Options)
            tValeurs(i) = oMatch.Value
            i += 1
        Next
        Array.Sort(tCles, tValeurs)
        'On replace les valeurs dans le texte dans l'ordre des matchs
        i = 0
        Dim Delta As Integer = 0
        For Each oMatch As Match In oColMatch
            'On applique la condition vbscript en cours de route pour assurer la correspondance des index...
            Dim bRetenu As Boolean = True
            If Me.Condition <> "" Then bRetenu = oCode.EvalCondition(oMatch, Me.Condition)
            If bRetenu Then
                Chaine = Chaine.Remove(oMatch.Index + Delta, oMatch.Length)
                Chaine = Chaine.Insert(oMatch.Index + Delta, tValeurs(i))
                Delta += tValeurs(i).Length - oMatch.Length
            End If
            i += 1
        Next
        Return Chaine
    End Function

    Public Sub Marquer(ByRef oRichText As Windows.Forms.RichTextBox)
        oRichText.SelectAll()
        oRichText.SelectionColor = System.Drawing.Color.Black
        oRichText.SelectionBackColor = System.Drawing.Color.White
        Call MarquerCumulatif(oRichText)
    End Sub

    Public Sub MarquerCumulatif(ByRef oRichText As Windows.Forms.RichTextBox)
        Dim Options As RegexOptions = RegexOptions.Multiline
        Dim oColMatch As MatchCollection
        Dim oCode As New ClassMacro 'Pour évaluation des conditions
        Dim CoulFP As Color = System.Drawing.ColorTranslator.FromHtml(Me.CoulFondPrimaire)
        Dim CoulFS As Color = System.Drawing.ColorTranslator.FromHtml(Me.CoulFondSecondaire)
        Dim CoulTP As Color = System.Drawing.ColorTranslator.FromHtml(Me.CoulTextePrimaire)
        Dim CoulTS As Color = System.Drawing.ColorTranslator.FromHtml(Me.CoulTexteSecondaire)
        If Me.SensibleCasse = Boolean.FalseString Then Options = Options Or RegexOptions.IgnoreCase
        If Me.Multi = Boolean.TrueString Then Options = Options Or RegexOptions.Singleline
        Try
            oColMatch = System.Text.RegularExpressions.Regex.Matches(oRichText.Text, Me.Masque, Options)
        Catch ex As Exception
            MsgBox("Expression régulière invalide " & Me.Masque, MsgBoxStyle.Exclamation)
            Exit Sub
        End Try
        For Each oMatch As Match In oColMatch
            'Condition vbScript
            Dim bRetenu As Boolean = True
            If Me.Condition <> "" Then bRetenu = oCode.EvalCondition(oMatch, Me.Condition)
            If bRetenu Then
                For iIndex As Integer = 0 To oMatch.Groups.Count - 1
                    oRichText.Select(oMatch.Groups(iIndex).Index, oMatch.Groups(iIndex).Length)
                    If iIndex = 0 Then
                        'Match
                        oRichText.SelectionColor = CoulTP
                        If Commun.TestRegex(oMatch.Value, "#[0-9a-f]{6}") And (Me.AutoCoulTextePrimaire = Boolean.TrueString) Then
                            oRichText.SelectionColor = System.Drawing.ColorTranslator.FromHtml(oMatch.Value)
                        End If
                        oRichText.SelectionBackColor = CoulFP
                    Else
                        'SubMatch
                        oRichText.SelectionColor = CoulTS
                        'On alterne la couleur avec deux tons plus bas pour distinguer les submatch collés
                        If iIndex Mod 2 = 0 Then
                            oRichText.SelectionBackColor = CoulFS
                        Else
                            oRichText.SelectionBackColor = ControlPaint.LightLight(CoulFS)
                        End If
                        'Propagation des submatch
                        If Me.Propager = Boolean.TrueString And oMatch.Groups(iIndex).Value <> "" Then
                            Dim iStart As Integer = 1
                            Dim iPos As Integer
                            Do
                                iPos = oRichText.Text.IndexOf(oMatch.Groups(iIndex).Value, iStart)
                                If iPos <> -1 Then
                                    oRichText.Select(iPos - 1, oMatch.Groups(iIndex).Length)
                                    oRichText.SelectionColor = CoulTP
                                    If iIndex Mod 2 = 0 Then
                                        oRichText.SelectionBackColor = CoulFS
                                    Else
                                        oRichText.SelectionBackColor = ControlPaint.LightLight(CoulFS)
                                    End If
                                    iStart = iPos + 1
                                End If
                            Loop Until iPos = -1
                        End If
                    End If
                Next
            End If
        Next
    End Sub

    Public Function Test(ByVal Chaine As String) As Boolean
        'Modif 13 mars 2012 - Tenir compte de la condition vbscript
        Dim Options As RegexOptions = RegexOptions.Multiline
        Dim oColMatch As MatchCollection
        Dim oCode As New ClassMacro 'Pour évaluation des conditions
        Dim bTest As Boolean
        If Me.SensibleCasse = Boolean.FalseString Then Options = Options Or RegexOptions.IgnoreCase
        Try
            oColMatch = System.Text.RegularExpressions.Regex.Matches(Chaine, Me.Masque, Options)
            If (oColMatch.Count = 1) Then
                bTest = (oColMatch.Item(0).Value.ToUpper = Chaine.ToUpper)
                If bTest And (Me.Condition <> "") Then bTest = oCode.EvalCondition(oColMatch.Item(0), Me.Condition)
                Return bTest
            End If
            Return False
        Catch ex As Exception
            MsgBox("Expression régulière invalide " & Me.Masque, MsgBoxStyle.Exclamation)
            Return False
        End Try
    End Function
End Class
